package net.chenlin.dp.ids.server.util;

import net.chenlin.dp.ids.common.constant.IdsConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * redis工具类
 * @author zcl<yczclcn@163.com>
 */
public class RedisUtil {

    private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);

    private static ShardedJedisPool shardedJedisPool;

    private static ReentrantLock REDIS_INIT_LOCK = new ReentrantLock(false);

    private static final long REDIS_LOCK_TIMEOUT = 2;

    private static String hostAndPort;

    /**
     * 初始化地址
     * @param hostAndPort
     */
    public static void init(String hostAndPort) {
        RedisUtil.hostAndPort = hostAndPort;
    }

    /**
     * 初始化连接池，获取redis连接
     * @return
     */
    private static ShardedJedis getInstance() {
        if (shardedJedisPool == null) {
            try {
                if (REDIS_INIT_LOCK.tryLock(REDIS_LOCK_TIMEOUT, TimeUnit.SECONDS)) {
                    try {
                        if (shardedJedisPool == null) {
                            // jedis pool config
                            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
                            jedisPoolConfig.setMaxTotal(200);
                            jedisPoolConfig.setMaxIdle(50);
                            jedisPoolConfig.setMinIdle(8);
                            jedisPoolConfig.setMaxWaitMillis(10000);
                            jedisPoolConfig.setTestOnBorrow(true);
                            jedisPoolConfig.setTestOnReturn(true);
                            jedisPoolConfig.setTestWhileIdle(true);
                            jedisPoolConfig.setTimeBetweenEvictionRunsMillis(30000);
                            jedisPoolConfig.setNumTestsPerEvictionRun(10);
                            jedisPoolConfig.setMinEvictableIdleTimeMillis(60000);
                            // jedis shard info
                            List<JedisShardInfo> jedisShardInfoList = new LinkedList<>();
                            String[] addrArr = hostAndPort.split(",");
                            for (String addr : addrArr) {
                                String[] addrInfo = addr.split(":");
                                String hostname = addrInfo[0];
                                int port = Integer.parseInt(addrInfo[1]);
                                JedisShardInfo jedisShardInfo = new JedisShardInfo(hostname, port, 10000);
                                jedisShardInfoList.add(jedisShardInfo);
                            }
                            shardedJedisPool = new ShardedJedisPool(jedisPoolConfig, jedisShardInfoList);
                            logger.info("RedisUtil init ShardedJedisPool success.");
                        }
                    } finally {
                        REDIS_INIT_LOCK.unlock();
                    }

                }
            } catch (InterruptedException e) {
                logger.error("RedisUtil lock exception:", e);
            }
        }
        if (shardedJedisPool == null) {
            throw new NullPointerException("RedisUtil.shardedJedisPool is null.");
        }
        return shardedJedisPool.getResource();
    }

    /**
     * set string 设置字符串
     * @param key
     * @param val
     * @param expire
     * @return
     */
    public static String set(String key, String val, int expire) {
        try(ShardedJedis client = getInstance()) {
            return client.setex(key, expire, val);
        } catch (Exception e) {
            logger.info("RedisUtil.set", e);
        }
        return null;
    }

    /**
     * set string：默认过期时间30分钟
     * @param key
     * @param val
     * @return
     */
    public static String set(String key, String val) {
        return set(key, val, IdsConst.REDIS_EXPIRE_TIME);
    }

    /**
     * get value 获取字符串值
     * @param key
     * @return
     */
    public static String get(String key) {
        try(ShardedJedis client = getInstance()) {
            return client.get(key);
        } catch (Exception e) {
            logger.info("RedisUtil.get", e);
        }
        return null;
    }

    /**
     * del 删除
     * @param key
     * @return 删除个数
     */
    public static Long del(String key) {
        try(ShardedJedis client = getInstance()) {
            return client.del(key);
        } catch (Exception e) {
            logger.info("RedisUtil.del", e);
        }
        return 0L;
    }

    /**
     * expire 设置过期时间
     * @param key
     * @param expire
     * @return 1：设置成功，0：失败
     */
    public static Long expire(String key, int expire) {
        try(ShardedJedis client = getInstance()) {
            return client.expire(key, expire);
        } catch (Exception e) {
            logger.info("RedisUtil.expire", e);
        }
        return 0L;
    }

    /**
     * expireAt 设置过期时间戳
     * @param key
     * @param timestamp
     * @return
     */
    public static Long expireAt(String key, long timestamp) {
        try(ShardedJedis client = getInstance()) {
            return client.expireAt(key, timestamp);
        } catch (Exception e) {
            logger.info("RedisUtil.expireAt", e);
        }
        return 0L;
    }

    /**
     * 是否存在key
     * @param key
     * @return true：存在，false：不存在
     */
    public static Boolean exists(String key) {
        try(ShardedJedis client = getInstance()) {
            return client.exists(key);
        } catch (Exception e) {
            logger.info("RedisUtil.exists", e);
        }
        return false;
    }

}
